package com.ysten.basic.common.log.listener;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.hibernate.ejb.event.EJB3PostUpdateEventListener;
import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.persister.entity.EntityPersister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ysten.basic.common.log.config.PropertyLogConfiguration;
import com.ysten.basic.common.log.util.OperationType;
import com.ysten.basic.common.log.util.PropertyLogConstants;
import com.ysten.basic.common.log.util.PropertyLogUtils;

/**
 * <<记录表-更新 日志>>
 * 
 * @author 陆小凤
 * @version [1.0, 2015年9月14日]
 */
@SuppressWarnings({"serial"})
public class PostUpdateEventListener extends EJB3PostUpdateEventListener
{
    
    private static final Logger logger = LoggerFactory.getLogger(PostUpdateEventListener.class);
    
    @Override
    public void onPostUpdate(PostUpdateEvent event)
    {
        Map<String, List<String>> configuration = PropertyLogConfiguration.INSTANCE.getConfiguration();
        
        String entityName = event.getEntity().getClass().getSimpleName();
        if (!configuration.containsKey(entityName))
        {
            return;
        }
        
        Map<String, Object> map = Maps.newHashMap();
        try
        {
            map = getContent(event, configuration.get(entityName));
            PropertyLogUtils.processNormal(map, event.getSession().connection(), OperationType.UPDATE);
        }
        catch (Exception e)
        {
            logger.error("process postUpdate error.", e);
        }
        
        super.onPostUpdate(event);
    }
    
    private Map<String, Object> getContent(PostUpdateEvent event, List<String> propertyList)
        throws IllegalArgumentException, IllegalAccessException, InstantiationException, ClassNotFoundException
    {
        Map<String, Object> map = Maps.newHashMap();
        EntityPersister persister = event.getPersister();
        Object entity = event.getEntity();
        
        // 获取操作表名称
        Serializable[] serializables = persister.getPropertySpaces();
        map.put(PropertyLogConstants.KEY_TABLENAME, serializables[0]);
        
        // 获取操作数据主键、实体属性
        String identifierPropertyName = persister.getIdentifierPropertyName();
        Field[] declaredFields = entity.getClass().getDeclaredFields();
        
        // 封装主键
        String fieldName = null;
        for (int i = 0; i < declaredFields.length; i++)
        {
            fieldName = declaredFields[i].getName();
            if (fieldName.equals(identifierPropertyName))
            {
                List<Map<String, Object>> pkList = Lists.newArrayList();
                // PK is Primitive
                if (!persister.getPropertyType(fieldName).isEntityType())
                {
                    Map<String, Object> pkMap = Maps.newHashMap();
                    declaredFields[i].setAccessible(true);
                    pkMap.put(fieldName, declaredFields[i].get(entity));
                    pkList.add(pkMap);
                }
                else
                {
                    // PK is Obejct
                    Class<?> obj = event.getId().getClass();
                    Field[] objFields = obj.getDeclaredFields();
                    for (int j = 0; j < objFields.length; j++)
                    {
                        if (objFields[j].getName().equals("serialVersionUID"))
                        {
                            continue;
                        }
                        objFields[j].setAccessible(true);
                        Map<String, Object> pkMap = Maps.newHashMap();
                        pkMap.put(objFields[j].getName(), objFields[j].get(event.getId()));
                        pkList.add(pkMap);
                    }
                }
                
                map.put(PropertyLogConstants.KEY_PKNAME, pkList);
            }
        }
        
        // 封装变化的数据
        StringBuilder oldStateBuilder = new StringBuilder();
        StringBuilder newStateBuilder = new StringBuilder();
        for (int i = 0; i < event.getState().length; i++)
        {
            String propertyName = persister.getPropertyNames()[i];
            
            // 如果过滤集合不为空且属性不需要被过滤,处理下一个
            if (!CollectionUtils.isEmpty(propertyList) && !propertyList.contains(propertyName))
            {
                continue;
            }
            
            // 如果是集合或者对象,处理下一个
            if (persister.getPropertyType(propertyName).isCollectionType()
                || persister.getPropertyType(propertyName).isEntityType())
            {
                continue;
            }
            
            Object oldValue = event.getOldState()[i];
            Object newValue = event.getState()[i];
            
            if ((null == oldValue && null != newValue) || (null != oldValue && null == newValue)
                || (null != oldValue && null != newValue && !(oldValue.toString()).equals(newValue.toString())))
            {
                if (!StringUtils.isEmpty(oldStateBuilder.toString()))
                {
                    oldStateBuilder.append("$");
                }
                if (!StringUtils.isEmpty(newStateBuilder.toString()))
                {
                    newStateBuilder.append("$");
                }
                
                oldStateBuilder.append(propertyName).append("=").append(oldValue);
                newStateBuilder.append(propertyName).append("=").append(newValue);
                
            }
            
        }
        map.put(PropertyLogConstants.KEY_PREVIOUS_PROPERTY, oldStateBuilder.toString());
        map.put(PropertyLogConstants.KEY_AFTER_PROPERTY, newStateBuilder.toString());
        
        return map;
    }
}